﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Threading;

namespace MaiYao
{
    public enum 任务名_
    {
        无,
        开始挂机,
        去海岛存药,
        去沙城买药,
        开始买药,
        仓库取药,
        准备捡药,
        回海岛休息,
        测试,
    }

    public class 挂机人物
    {
        public IntPtr 句柄 = IntPtr.Zero;
        public 挂机项目_ 挂机项目 = 挂机项目_.无;
        public int 角色包裹空格数量 = 0;
        public int 扔药剩余数量 = 0;
        public ulong 角色金币数量 = 0;
        public 坐标_ 仓库管理员坐标 = 坐标_.零值();
        public bool 药已经取完 = false;
        public bool 已经捡满了 = false;
        public bool 本包已经扔完 = false;
        public int 回海岛休息时长 = 10000;
        public int 回海岛休息次数 = 0;
        public string 回岛原因 = null;
        public 内存读取器 读内存;
        public Point 窗口零点坐标 = Point.Empty;
        public CancellationTokenSource cts;

        public 挂机人物(IntPtr 句柄, CancellationTokenSource cts, 挂机项目_ 挂机项目, int 角色包裹空格数量, int 扔药剩余数量, ulong 角色金币数量, 坐标_ 仓库管理员坐标)
         : this(句柄, cts, 挂机项目, 角色包裹空格数量, 角色金币数量, 仓库管理员坐标)
        {
            this.扔药剩余数量 = 扔药剩余数量;
        }

        public 挂机人物(IntPtr 句柄, CancellationTokenSource cts, 挂机项目_ 挂机项目, int 角色包裹空格数量, ulong 角色金币数量, 坐标_ 仓库管理员坐标)
        {
            this.句柄 = 句柄;
            this.读内存 = new 内存读取器(this.句柄);
            this.挂机项目 = 挂机项目;
            this.角色包裹空格数量 = 角色包裹空格数量;
            this.角色金币数量 = 角色金币数量;
            this.仓库管理员坐标 = 仓库管理员坐标;
            this.窗口零点坐标 = 窗口_.客户端坐标转为屏幕坐标(句柄, new Point(0, 0));
            this.cts = cts;
        }

        public bool 连续执行任务 = false;
        public bool 出现异常不在处理 = false;

        public List<Func<任务名_>> 动作 = new List<Func<任务名_>>();

        public 任务名_ 当前任务名 = 任务名_.开始挂机; //任务名_.测试_; // 
        public 任务名_ 上个任务名 = 任务名_.无;
        public 任务名_ 应恢复任务 = 任务名_.无;


        public List<挂机人物> 人物列表;

        public void 输出(string 内容)
        {
            其他_.打印(this.获取角色名() + " : " + 内容);
        }

        public bool 执行(List<挂机人物> 人物列表)
        {
            if (this.出现异常不在处理) return false;
            bool 多端执行 = 人物列表.Count > 1;
            if (this.当前任务名 == 任务名_.测试)
            {
                操作.识别金币数量(this);
                return false;
            }
            if (this.人物列表 == null) this.人物列表 = 人物列表;

            if (this.当前任务名 == 任务名_.无)
            {
                其他_.延迟(其他_.时长_1000);
                this.输出("无任务");
                return false;
            }
            if (this.当前任务名 == 任务名_.开始挂机)
            {
                if (this.挂机项目 == 挂机项目_.买药)
                {
                    this.当前任务名 = 任务名_.去海岛存药;
                    return true;
                }
                if (this.挂机项目 == 挂机项目_.扔药)
                {
                    this.当前任务名 = 任务名_.仓库取药;
                    return true;
                }
                if (this.挂机项目 == 挂机项目_.捡药)
                {
                    this.当前任务名 = 任务名_.准备捡药;
                    return true;
                }
                return false;
            }
            else
            {
                准备动作();

                if (动作.Count <= 0)
                {
                    return false;
                }

                窗口_.设为前台窗口(this.句柄);
                其他_.延迟(其他_.时长_1000);
                this.窗口零点坐标 = 窗口_.客户端坐标转为屏幕坐标(句柄, new Point(0, 0));
                其他_.延迟(其他_.时长_200);

                for (var ii = 0; ii < 动作.Count; ii++)
                {
                    var fc = 动作[ii];
                    this.上个任务名 = this.当前任务名;
                    try
                    {
                        this.当前任务名 = fc();
                    }
                    catch
                    {
                        this.输出("发生错误, 挂机进程停止");
                        this.当前任务名 = 任务名_.无;
                        return false;
                    }
                }
                return true;
            }
        }

        private void 添加动作(Func<任务名_> func)
        {
            this.动作.Add(func);
        }

        private void 清除动作()
        {
            this.动作.Clear();
        }

        public string 获取角色名()
        {
            return this.挂机项目 == 挂机项目_.买药 ? "买药" : this.挂机项目 == 挂机项目_.捡药 ? "捡药" : "扔药";
        }

        public void 准备动作(bool 清除原有动作 = true)
        {
            if (清除原有动作) this.清除动作();
            this.输出("当前任务: " + this.当前任务名.ToString());

            switch (this.当前任务名)
            {
                case 任务名_.仓库取药:
                    {
                        this.添加动作(() => 操作_.仓库取药(this));
                        return;
                    }
                case 任务名_.准备捡药:
                    {
                        this.添加动作(() => 操作_.准备捡药(this));
                        return;
                    }
                case 任务名_.去沙城买药:
                    {
                        this.添加动作(() => 操作_.去沙城买药(this));
                        return;
                    }
                case 任务名_.开始买药:
                    {
                        this.添加动作(() => 操作_.开始买药(this));
                        return;
                    }
                case 任务名_.去海岛存药:
                    {
                        this.添加动作(() => 操作_.去海岛存药(this));
                        return;
                    }
                case 任务名_.回海岛休息:
                    {
                        this.添加动作(() => 操作_.回海岛休息(this));
                        return;
                    }
            }
            return;
        }
    }

    public static class 操作_
    {
        public static 任务名_ 仓库取药(挂机人物 人物)
        {
            return 操作.打开仓库取药(人物);
        }

        public static 任务名_ 准备捡药(挂机人物 人物)
        {
            if (人物.人物列表.Count > 1)
            {
                var 扔药的 = 人物.人物列表.Find(r => r.挂机项目 == 挂机项目_.扔药);
                if (!扔药的.本包已经扔完)
                {
                    return 任务名_.准备捡药;
                }
                if (扔药的.药已经取完)
                {
                    return 任务名_.无;
                }
            }
            坐标_ p1, p2;
            do
            {
                p1 = 操作.获取当前坐标(人物);
                if (人物.人物列表.Count > 1)
                {
                    其他_.延迟(其他_.时长_5000);
                }
                else
                {
                    其他_.延迟(其他_.时长_10000);
                }
                p2 = 操作.获取当前坐标(人物);
            }
            while (p1 != p2);

            if (人物.人物列表.Count > 1)
            {
                var 扔药的 = 人物.人物列表.Find(r => r.挂机项目 == 挂机项目_.扔药);
                if (扔药的.已经捡满了)
                {
                    return 任务名_.无;
                }
            }
            return 操作.打开仓库存药(人物);
        }

        public static 任务名_ 开始买药(挂机人物 人物)
        {
            if (!其他_.循环判断(() => 操作.确认药店已经打开(人物), 2, 400))
            {
                人物.应恢复任务 = 任务名_.去海岛存药;
                人物.回岛原因 = "没能点中药店";
                return 任务名_.回海岛休息;
            }

            return 操作.沙城药店买药(人物);
        }

        public static 任务名_ 去沙城买药(挂机人物 人物)
        {
            return 操作.去沙城药店(人物);
        }

        public static 任务名_ 去海岛存药(挂机人物 人物)
        {
            操作.去海岛仓库(人物);
            return 操作.打开海岛仓库一键存药(人物);
        }

        public static 任务名_ 回海岛休息(挂机人物 人物)
        {
            操作.去海岛仓库(人物);
            if (人物.回岛原因 != null)
            {
                人物.输出(人物.回岛原因);
                人物.回岛原因 = null;
            }
            if (人物.回海岛休息时长 == 0 || 人物.回海岛休息次数 > 10)
            {
                人物.输出("出现意外停止挂机");
                return 任务名_.无;
            }

            其他_.运行速率 += 0.1;
            人物.回海岛休息次数++;
            其他_.延迟(人物.回海岛休息时长);
            var 恢复任务 = 人物.应恢复任务;
            人物.应恢复任务 = 任务名_.无;
            return 恢复任务;
        }
    }
}
